昨天學習完 Go 語言中的核心型別,但若想要建立更複雜的資料,那就需要搭配複合型別,今天就先來介紹第一個複合型別- 陣列 (array) 。
今天我想要把水果分類成,喜歡的、不喜歡的兩種,然後把他們裝在兩個集合裡,在 Go 語言裡有所謂的 集合型別(collection types) ,內包含 陣列 (array) 、 切片 (slice) 和 映射表 (map) 來將多筆資料集中擺放,當然也可以方便我們走訪或是處理資料。
最標準的定義陣列時 一定 需要 陣列長度 及 資料型別 ,資料型別可以是任意型別,但一次只能有一種型別。
[<長度>]<型別>
補充:
若定義時沒寫陣列長度一樣可以宣告成功,但他就不會是陣列, Go 語言會認為他是切片 (slice)。
當然我們也可以賦予陣列初始值,若沒有初始值則會是其型別的 零值 ,上面說定義陣列時必須要給予長度,但當有給予初始值時, Go 語言會根據初始值的數量來推測其陣列長度,但不是這樣就可以完全不寫喔!而是把陣列長度的地方換成[...],讓 Go 語言去推測。
[<長度>]<型別>{<初始值 1>,<初始值 2>,<初始值 3>,...<初始值 N>}
範例 1:
package main
import "fmt"
func array1() [5]int { // func 回傳一個長度為 5 型別為 int 的陣列
var arr [5]int // 定義一個長度為 5 型別為 int 的陣列(沒有賦予初始值,會自動以零值為其初始值)
return arr // 回傳 arr
}
func array2() [3]int { // func 回傳一個長度為 3 型別為 int 的陣列
arr := [3]int{1,2,3} // 定義一個長度為 3 型別為 int 的陣列(有賦予初始值,會以賦予的值為其初始值)
return arr // 回傳 arr
}
func array3() [4]int { // func 回傳一個長度為 4 型別為 int 的陣列
arr := [4]int{9} // 定義一個長度為 4 型別為 int 的陣列(只有賦予一個初始值,其餘會以零值為初始值)
return arr // 回傳 arr
}
func array4() [6]int { // func 回傳一個長度為 6 型別為 int 的陣列
arr := [...]int{1,2,3,9,8,7} // 定義一個長度為 6 型別為 int 的陣列(有賦予初始值,將陣列長度省略為...)
return arr // 回傳 arr
}
func main() {
fmt.Println("array1:",array1())
fmt.Println("array2:",array2())
fmt.Println("array3:",array3())
fmt.Println("array4:",array4())
}
範例 1(執行結果):
array1: [0 0 0 0 0]
array2: [1 2 3]
array3: [9 0 0 0]
array4: [1 2 3 9 8 7]
這時我持續開開心心的定義一個陣列如下:
範例 2:
package main
import "fmt"
func array5() [6]int { // func 回傳一個長度為 6 型別為 int 的陣列
arr := [...]int{1,2,3} // 將陣列長度以...省略讓 Go 語言自己推測,且賦予 3 個初始值)
return arr // 回傳 arr
}
func main() {
fmt.Println("array5:",array5())
}
範例 2(執行結果):
cannot use arr (variable of type [3]int) as type [6]int in return statement
結果直接噴錯了QQ,仔細思考或是看錯誤訊息其實不難發現,你只給予陣列三個初始值, Go 語言自己推測這是一個長度為 3 的陣列,但是在你又希望 func 回傳一個長度為 6 型別為 int 的陣列,這不是強人所難嗎?所以解決方法有二:
陣列與陣列同時也可以拿來比較,但前提是他們要 長度相同 及 資料型別 ,就像你不會拿著五顆蘋果去問媽媽說這是兩顆蘋果嗎? (這個例子好無言,但是又好有畫面哈哈)
那接下來我們就來用各種方式來比對我們的陣列吧!
範例 3:
package main
import "fmt"
func compareArrays() (bool,bool,bool) { // func 回傳三個布林值
arr1 := [...]int{1,2,3}
var arr2 [3]int
arr3 := [...]int{0,0,0}
arr4 := [3]int{1}
return arr1 == arr2, arr2 == arr3, arr1 == arr4 // 回傳 arr 是否兩兩相等
}
func main() {
compare1,compare2,compare3 := compareArrays()
fmt.Println("arr1 == arr2:",compare1)
fmt.Println("arr2 == arr3:",compare2)
fmt.Println("arr1 == arr4:",compare3)
}
範例 3(執行結果):
arr1 == arr2: false
arr2 == arr3: true
arr1 == arr4: false
這時我又開開心心,想來比較兩個陣列:
範例 4:
package main
import "fmt"
func compareArrays() (bool) { // func 回傳三個布林值
arr3 := [...]int{0,0,0}
var arr5 [6]int
return arr3 == arr5 // 回傳 arr 是否兩兩相等
}
func main() {
compare4 := compareArrays()
fmt.Println("arr3 == arr5:",compare4)
}
範例 4(執行結果):
invalid operation: arr3 == arr5 (mismatched types [3]int and [6]int)
啊!怎麼又錯了~錯誤訊息說 [3]int 和 [6]int 不能相比,原來我就是上面那個拿著不同顆蘋果問媽媽的人QQ
相信大家應該知道如何修改,這邊就交給大家自行修改了!
若想要在 Go 語言中比較集合,用 陣列 (array) 是非常方便的,而文章開頭說到的其他 集合型別(collection types) ,如 切片 (slice) 或 映射表 (map) 是無法像陣列一樣這樣比較整個集合的,他們只能一一比對集合中的元素值。
上面有學習到我們可以賦予陣列起始值,但有時候我只想要對陣列其中幾個索引值賦予初始值,其餘皆是零值,這也是可行的,且當你對索引賦予初始值時,不一定需要按照順序, Go 語言在這方面就有許多彈性。
[<長度>]<型別>{<索引 1>: <初始值 1>,<索引 2>:<初始值 2>,...<索引 n>:<初始值 n>}
範例 5:
package main
import "fmt"
var(
arr1 [5]int
arr2 = [...]int{4:0} // 若使用...讓 Go 推算陣列長度,即使索引 4 一樣是零值,還是要賦予初始值,讓 Go 有推算根據
arr3 = [5]int{4:40, 2:20, 30} // 索引賦予初始值不按照順序也 ok ,且若是沒有給予索引,則會自動推算在前一個索引 +1
)
func main (){
fmt.Println("arr1:",arr1)
fmt.Println("arr2:",arr2)
fmt.Println("arr3:",arr3)
fmt.Println(arr1 == arr2) // 雖寫法不同,但實質上兩個陣列內容相同
}
範例 5(執行結果):
arr1: [0 0 0 0 0]
arr2: [0 0 0 0 0]
arr3: [0 0 20 30 40]
true
剛剛前面講了好多次的索引,索引到底是什麼?我通常把它想成在陣列裡的位置編號,陣列裡的第一個元素的位置編號永遠會從 0 起算,且每往下一個元素,其索引值都是加一,這使我們可以很方便地從陣列中取出元素值,如此一來若要拿陣列的最後一個元素也變得簡單許多,只需要把陣列長度-1,即可得出最後一個元素的值。
<值> = <陣列>[<索引>]
範例 6:
package main
import "fmt"
func murmur() string{
arr := [...]string{
"我最愛",
"水果",
"芒果",
"是",
"的",
}
return fmt.Sprintln(arr[0],arr[4],arr[1],arr[3],arr[2]) // fmt.Sprintln 將字串格式化
}
func main() {
fmt.Print(murmur()) // 利用索引值將陣列內的字串,拼成我的 murmur
}
範例 6(執行結果):
我最愛 的 水果 是 芒果
陣列的值可以讀,就也可以寫入值到陣列中,有時候我們會先定義好一個陣列,然後當有資料的時候,再將值寫入陣列。
<陣列>[<索引>] = <值>
讓我們拿剛剛的範例六稍作修改...
範例 7:
package main
import "fmt"
func murmur() string{
arr := [...]string{
"我最愛",
"水果",
"芒果",
"是",
"的",
}
arr[2] = "榴槤" // 將索引 2 寫入新的值
arr[0] = "我最討厭" // 將索引 0 寫入新的值
return fmt.Sprintln(arr[0],arr[4],arr[1],arr[3],arr[2]) // fmt.Sprintln 將字串格式化
}
func main() {
fmt.Print(murmur())
}
範例 7(執行結果):
我最討厭 的 水果 是 榴槤
前面有說到陣列的索引值永遠都是從 0 起算,且每多一個元素,索引值都是 +1 ,因為其特性用迴圈來走訪陣列就是一個常用的做法,我們可以使用迴圈來將陣列中的每個元素做相同處理,如:對一個 int 型態的陣列每個元素 +5。
以下先來複習一下迴圈怎麼寫
for i := 0; i < len(<陣列>); i++ { //使用 len(<陣列>) 來計算陣列的長度
// 迴圈內要對陣列做的事
}
範例 8:
package main
import "fmt"
func add5() string {
addString := ""
arr := [5]int{1,2,3,4,5}
for i := 0; i < len(arr); i++ { //使用 len() 來計算陣列 arr 的長度
arr[i] = arr[i] + 5
addString += fmt.Sprintln("索引值",i,":","元素值",arr[i])
}
return addString
}
func main() {
fmt.Println(add5())
}
範例 8(執行結果):
索引值 0 : 元素值 6
索引值 1 : 元素值 7
索引值 2 : 元素值 8
索引值 3 : 元素值 9
索引值 4 : 元素值 10
那今天陣列就介紹到這邊啦!不知道大家會不會跟我一樣覺得陣列有點麻煩,每次都一定需要陣列長度,但總會遇到我無法在一開始就確定陣列長度的狀況發生,所以 Go 語言就有一個切片(slice),他跟陣列非常相似,但又可以解決陣列的一些麻煩點,那我們就明天繼續來學習這個神奇的切片 (slice) 吧!